/* 
Plugin banuje gracza przez dodanie wpisu do configa.
W pliku configs/amx_cban.ini mozna zdefiniowac nazwy konfigow (bez .cfg)
W przypadku nie podania nazw zapisywane beda ponizsze konfigi:
	hl
	save/custom
	save/save
	maps/maps
	maps/de_dust2
	cstrike
	models/mdl
	
CVAR:
amx_cban_active (domyslnie 1)
	0 - Wylacza plugin
	1 - Wlacza plugin
	
amx_cban_kick (domyslnie 1)
	0 - Przy banie do klienta bedzie wyslana komenda disconnect (zadnych informacji)
	1 - Przy banie bedzie komenda serwera kick z powodem "Do grania na tym serwerze potrzebujesz konta STEAM"

amx_cban_with_zban (domyslnie 0)
	0 - Brak Integracji z "Zabijaka No Damage Ban"
	1 - Integracja z "Zabijaka No Damage Ban" - Przy amx_zban banuje tez na cfg
	
amx_cban_log (domyslnie 1)
	0 - Nie zapisuje logow o banie/unbanie
	1 - Zapisuje logi
	
amx_cban_info (domyslnie hl_num)
	Nazwa w set_info
	
amx_cban_skip_steam (domyslnie 1)
	0 - Banuje wszystkich graczy
	1 - Nie banuje graczy ze Steamem
	
	
Komendy:
	amx_cban [nick lub #authid] 	- Banuje gracza
	amx_cbanmenu 			- Pokazuje menu do banowania graczy
	amx_cunbanmenu [ID] 		- Pokazuje liste 30 banow z mozliwoscia odbanowania 
					(jesli ID zostanie podane pokaze 30 banow przed podanym 
					numerem, jesli nie - 30 ostatnich banow
				
*/

#include <amxmodx>
#include <amxmisc>
#include <nvault>

#define PLUGIN "Zabijaka Config Ban"
#define VERSION "1.0"
#define AUTHOR "Zabijaka"

#define MAX_CONFIGS 10
#define CFG_NAME_LEN 17
#define MAX_NAME_LEN 33
#define TASK_WRITE_CONFIGS 33
#define TASK_CLEAR_CONSOLE 66
#define TASK_DISCONNECT 99
#define TASK_SHOW_INFO 133
#define TASK_CLEAR_INFO 166
#define TASK_CHECK_FOR_BAN 199
#define TASK_CHECK_INFO 233
#define TASK_SET_INFO 266
#define MAX_PLAYERS 33
#define MAX_UNBAN_POS 30

new gMaxPlayers;
new gNextBanId;
new gNvaultHandle;

new gConfigFiles[MAX_CONFIGS + 1][CFG_NAME_LEN];
new gNumOfConfigs = 0;
new gBannedPlayers[MAX_PLAYERS];
new gPlayersConfig[MAX_PLAYERS];


new const gAMX_CBAN[] = "amx_cban";
new const gAMX_CBAN_LOG[] = "amx_cban.log";
new const gNEXT_BAN_ID[]="NBID";
new const gInfoBanned[] = "Ban Id[%s] - Admin: %s [%s] zbanowal %s";
new const gInfoBanned2[] = "Ban Id[%s] - Ponowny ban dla: %s, Zbanowany byl: %s";
new const gInfoUnbanned[] = "%s [%s] odbanowal %s";
new const gTimeFormat[] = "%d/%m/%Y - %H:%M:%S";

new gCvarShowInfo;
new gCvarInfo;
new gCvarLog;
new gCvarSkipSteam;
new gCvarActive;


new gTmpBanId[16];
new gTmpTimestamp;

	
new const gCmdWriteCfg[] = "writecfg %s";
new const gCmdExecCfg[] = "exec %s.cfg";
new const gCmgClearConsole[] = "clear";

public plugin_init() {
	register_plugin(PLUGIN, VERSION, AUTHOR)
	register_clcmd(gAMX_CBAN, "amxCban", ADMIN_BAN, "<nick lub #authid>");
	register_clcmd("amx_cbanmenu", "cBanMenu", ADMIN_BAN);
	register_clcmd("amx_cunbanmenu", "cUnbanMenu", ADMIN_BAN, "[IdBana]");
	
	gCvarActive = register_cvar("amx_cban_active", "1");
	gCvarShowInfo = register_cvar("amx_cban_kick", "1");
	gCvarLog = register_cvar("amx_cban_log", "1");
	gCvarInfo = register_cvar("amx_cban_info","hl_num");
	gCvarSkipSteam = register_cvar("amx_cban_skip_steam", "1");
	
	new configsDir[64]
	get_configsdir(configsDir, 63)
	format(configsDir, 63, "%s/%s.ini", configsDir,gAMX_CBAN)
	loadSettings(configsDir);
	gMaxPlayers = get_maxplayers();
	
	gNvaultHandle = nvault_open(gAMX_CBAN);
	
	if(nvault_lookup(gNvaultHandle, gNEXT_BAN_ID,  gTmpBanId, charsmax(gTmpBanId),gTmpTimestamp)){
		gNextBanId = str_to_num(gTmpBanId) + 1;
	} else {
		gNextBanId = 1;
	}

}
public plugin_end(){
	nvault_close(gNvaultHandle);
}
public loadSettings(szFilename[])
{
	new File=fopen(szFilename,"r");
	new Text[CFG_NAME_LEN];
	if (File)
	{
		while (!feof(File) && gNumOfConfigs < MAX_CONFIGS)
		{
			fgets(File,Text,CFG_NAME_LEN-1);
			trim(Text);
			if (Text[0]==';') 
				continue;
			copy(gConfigFiles[gNumOfConfigs], CFG_NAME_LEN-1, Text);
			gNumOfConfigs ++;
		}
		
		fclose(File);
	}
	if(gNumOfConfigs == 0){
		copy(gConfigFiles[0], CFG_NAME_LEN-1, "hl");
		copy(gConfigFiles[1], CFG_NAME_LEN-1, "save/custom");
		copy(gConfigFiles[2], CFG_NAME_LEN-1, "save/save");
		copy(gConfigFiles[3], CFG_NAME_LEN-1, "maps/maps");
		copy(gConfigFiles[4], CFG_NAME_LEN-1, "maps/de_dust2");
		copy(gConfigFiles[5], CFG_NAME_LEN-1, "cstrike");
		copy(gConfigFiles[6], CFG_NAME_LEN-1, "models/mdl");
		gNumOfConfigs = 7;
	}
	return 1;
}

public setNextBanId(){
	gNextBanId++;
	new str[17];
	num_to_str(gNextBanId, str, 16);
	nvault_set(gNvaultHandle, gNEXT_BAN_ID, str);
}


public amxCban(id, level, cid){
	if(!get_pcvar_num(gCvarActive))
		return PLUGIN_HANDLED;
	if(cmd_access(id,level,cid,1)){
		new sPlayer[32];
		read_argv(1, sPlayer, charsmax(sPlayer));	
		new player = cmd_target(id, sPlayer, CMDTARGET_ALLOW_SELF);
		new banId = gNextBanId;
		setNextBanId();		
		banPlayerById(id, player,banId, 1);
	}
	return PLUGIN_HANDLED;
}

public cBanMenu(id, level, cid){
	if(!get_pcvar_num(gCvarActive))
		return PLUGIN_HANDLED;
	if(cmd_access(id,level,cid,1)){
		new menu = menu_create("\rZabijaka Config Ban Menu:", "menu_handler");
		new players[32];
		new num;
		get_players(players, num);
		new sName[64];
		new tempid;
		new sTempid[3];
		new iNum = 0;
		new skipSteam = get_pcvar_num(gCvarSkipSteam);
		
		for(new i=0;i< num;i ++){
			tempid = players[i];
			if(skipSteam){
				get_user_authid(tempid, sName, charsmax(sName));
				if(isValidSteam(sName))
				    continue;
			}
			sName[0] = 0;
			get_user_name(tempid, sName, 63);			
			num_to_str(tempid, sTempid, 2);
			menu_additem(menu, sName, sTempid, 0);
			iNum++;
		}
		if(iNum)
			menu_display(id, menu, 0);
		else{
			client_print(id, print_chat, "Brak Graczy");
			menu_destroy(menu);
		}
	}
	return PLUGIN_HANDLED;
}

public menu_handler(id, menu, item)
{
	if( item == MENU_EXIT )
	{
		menu_destroy(menu);
		return PLUGIN_HANDLED;
	}

	new data[6], szName[64];
	new acc, callback;
	menu_item_getinfo(menu, item, acc, data, charsmax(data), szName, charsmax(szName), callback);
	new tempid = str_to_num(data);	
	new banId = gNextBanId;
	setNextBanId();
	banPlayerById(id, tempid, banId,1);	
	menu_destroy(menu);
	return PLUGIN_HANDLED;
}

banPlayerById(admin, player, banId, doDisconnectPlayer = 1){	

	if(0 < player < gMaxPlayers && !gBannedPlayers[player]){
		
		new sBanId[17];
		new bannedPlayer[MAX_NAME_LEN];
		new bannedPlayerOld[MAX_NAME_LEN];
		new steam[MAX_NAME_LEN];
		new banPlayer = 1;
		get_user_name(player, bannedPlayer, MAX_NAME_LEN -1);
		if(get_pcvar_num(gCvarSkipSteam))
		{
			get_user_authid(player, steam, MAX_NAME_LEN -1);
			if(isValidSteam(steam)){
				banPlayer = 0;
				if(admin)
					client_print(admin, print_console, "Gracz %s posiada steama. Ban na cfg nie jest potrzebny", bannedPlayer);
			}
		}
		if(banPlayer){
			gBannedPlayers[player] = banId;
			set_task(0.2, "setInfo", player + TASK_SET_INFO);
			num_to_str(banId, sBanId, charsmax(sBanId));
			new timestamp;
			if(!nvault_lookup(gNvaultHandle, sBanId, bannedPlayerOld, MAX_NAME_LEN -1, timestamp)){
				nvault_set(gNvaultHandle, sBanId, bannedPlayer);
				copy(bannedPlayerOld, MAX_NAME_LEN -1, bannedPlayer);
			}
				
			client_cmd(player, gCmdWriteCfg, "org");
			set_task(0.5, "writeConfigs", TASK_WRITE_CONFIGS + player);
			if(doDisconnectPlayer) {
				set_task(3.0, "disconnectBannedPlayer", TASK_DISCONNECT + player);
			}
			if(get_pcvar_num(gCvarLog)){
				new name[MAX_NAME_LEN];
				if(admin) {
					get_user_name(admin, name, MAX_NAME_LEN -1);
					get_user_authid(admin, steam, MAX_NAME_LEN -1);
				} else {
					copy(name, MAX_NAME_LEN -1, "AMXBANS");
				}
				if(!equal(bannedPlayer, bannedPlayerOld)){
					log_to_file(gAMX_CBAN_LOG, gInfoBanned2, sBanId, bannedPlayer, bannedPlayerOld);			
				} else {
					log_to_file(gAMX_CBAN_LOG, gInfoBanned, sBanId, name, steam, bannedPlayer);			
				}
			}
		}
	}
}

public cUnbanMenu(id, level, cid){
	if(!get_pcvar_num(gCvarActive))
		return PLUGIN_HANDLED;
	if(cmd_access(id,level,cid,1)){
		new menu = menu_create("\rZabijaka Config UnBan Menu:", "unban_menu_handler");
		
		new timeStamp;
		new lastId = gNextBanId - 1;
		new vKey[17];
		new vData[37];
		new i=0;
		new mText[64];
		new timeStr[37];
		if(read_argc ( )  == 2){
			read_argv(1, vKey, charsmax(vKey));
			if(is_str_num(vKey)){
				lastId = str_to_num(vKey);
			}
		}
		
		while(i<MAX_UNBAN_POS && lastId >0) {
			
			num_to_str(lastId, vKey, charsmax(vKey));
			if(nvault_lookup(gNvaultHandle, vKey, vData, charsmax(vData), timeStamp)){
				format_time ( timeStr, 63, gTimeFormat, timeStamp) ;
				formatex(mText, charsmax(mText),"Id:%s. %s [%s]",vKey,  vData, timeStr);
				menu_additem(menu, mText, vKey, 0);
				i++
			}
			lastId--;
		}
		
		if(i)
			menu_display(id, menu, 0);
		else{
			client_print(id, print_chat, "Brak Graczy");
			menu_destroy(menu);
		}
	}
	return PLUGIN_HANDLED;
}

public unban_menu_handler(id, menu, item)
{
	if( item == MENU_EXIT )
	{
		menu_destroy(menu);
		return PLUGIN_HANDLED;
	}

	new  szName[64];
	new acc, callback;
	new vKey[17];
	menu_item_getinfo(menu, item, acc, vKey, charsmax(vKey), szName, charsmax(szName), callback);
	unBanPlayer(id, vKey);	
	menu_destroy(menu);
	return PLUGIN_HANDLED;
}
public unBanPlayer(id, const banId[]){
	new timeStamp;
	new vData[37];
	if(nvault_lookup(gNvaultHandle, banId, vData, charsmax(vData), timeStamp)){
		nvault_remove(gNvaultHandle, banId);
		client_print(id, print_chat, "Odbanowano %s",  vData);
		if(get_pcvar_num(gCvarLog)){
			new steam[MAX_NAME_LEN];
			new name[MAX_NAME_LEN];
			get_user_authid(id, steam, MAX_NAME_LEN -1);
			get_user_name(id, name, MAX_NAME_LEN - 1);
			log_to_file(gAMX_CBAN_LOG, gInfoUnbanned, name, steam, vData);
		}
		
	} else {
		client_print(id, print_chat, "Nie ma bana z numerem %s",  banId);
	}
}

isValidSteam(const steamId[]){
	if(strfind(steamId, "STEAMID_0:") ==0 || strfind(steamId, "STEAMID_1:") ==0)
		return 1;
	return 0;
}


public client_disconnect(id){
	gBannedPlayers[id] = 0;
	gPlayersConfig[id] = 0;
}
public client_connect(id) {
	if(!get_pcvar_num(gCvarActive))
		return PLUGIN_CONTINUE;

	if(!is_user_connected(id)){
		set_task(2.0, "client_connect", id);
		return PLUGIN_CONTINUE;
	}
	gBannedPlayers[id] = 0;
	gPlayersConfig[id] = 0;
	
	if(get_pcvar_num(gCvarSkipSteam)){
		new steam[MAX_NAME_LEN];
		get_user_authid(id, steam, MAX_NAME_LEN -1);
		if(isValidSteam(steam))
			return PLUGIN_CONTINUE;
		if(contain(steam, "PENDING")){			
			set_task(2.0, "checkForBan", id + TASK_CHECK_FOR_BAN);
			return PLUGIN_CONTINUE;
		}
	}
	checkForBan(id + TASK_CHECK_FOR_BAN)
	return PLUGIN_CONTINUE;
}

public checkForBan(id){
	new player = id - TASK_CHECK_FOR_BAN;
	if(gPlayersConfig[player] < gNumOfConfigs){		
		if(is_user_connected(player)){
			client_cmd(player, gCmdExecCfg, gConfigFiles[gPlayersConfig[player]]);
			set_task(0.2, "checkInfo", player + TASK_CHECK_INFO);
		}
	}
}

public checkInfo(id){	
	new player = id - TASK_CHECK_INFO;
	gPlayersConfig[player] = gPlayersConfig[player] + 1
	if(is_user_connected(player)) {
		new info[16];	
		new sBanInfo[17];
		get_pcvar_string( gCvarInfo, info, charsmax(info));
		get_user_info(player, info, sBanInfo, charsmax(sBanInfo));
		if(sBanInfo[0] && is_str_num(sBanInfo)){
			new value[MAX_NAME_LEN];
			new iTimestamp;
			if(nvault_lookup(gNvaultHandle, sBanInfo, value, charsmax(value), iTimestamp)){
				banPlayerById(-1, player, str_to_num(sBanInfo), 1);
				return 1;
			}
		}	
		clearConsole(player + TASK_CLEAR_CONSOLE);
		if(gPlayersConfig[player] < gNumOfConfigs)
			checkForBan(player + TASK_CHECK_FOR_BAN);\
	}
	return 0;
}



public writeConfigs(id) {
	new player = id - TASK_WRITE_CONFIGS;		
	new cfg[CFG_NAME_LEN];
	if(is_user_connected(player)) {
		for(new i=0;i<gNumOfConfigs;i++){
			copy(cfg, CFG_NAME_LEN -1, gConfigFiles[i]);
			client_cmd(player, gCmdWriteCfg, cfg);
		}
	}
	set_task(0.3, "setInfo", TASK_SET_INFO +  player);
	set_task(0.8, "clearConsole", TASK_CLEAR_CONSOLE +  player );
}

public clearConsole(id){
	new player = id - TASK_CLEAR_CONSOLE;
	if(is_user_connected(player))
		client_cmd(player, gCmgClearConsole);
}
public disconnectBannedPlayer(id){
	new player = id - TASK_DISCONNECT;
	if(is_user_connected(player)) {
		if(get_pcvar_num(gCvarShowInfo))
			server_cmd("kick #%d %s", get_user_userid(player), "Do grania na tym serwerze potrzebujesz konta STEAM");
		else 
			client_cmd(player, "disconnect");
	}
}

public setInfo(id){
	new player = id - TASK_SET_INFO
	new info[16];	
	get_pcvar_string( gCvarInfo, info, charsmax(info));
	new banId = gBannedPlayers[player];
	if(info[0]){
		if(banId)
			client_cmd(player, "setinfo %s ^"%d^"", info, banId);
		else
			client_cmd(player, "setinfo %s ^"^"", info);
	}
}

/* AMXX-Studio Notes - DO NOT MODIFY BELOW HERE
*{\\ rtf1\\ ansi\\ deff0{\\ fonttbl{\\ f0\\ fnil Tahoma;}}\n\\ viewkind4\\ uc1\\ pard\\ lang1045\\ f0\\ fs16 \n\\ par }
*/
